package vn.conghuy.talkwithme;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Random;

import vn.conghuy.talkwithme.android.utils.DatabaseHelper;
import vn.conghuy.talkwithme.android.utils.Utils;
import vn.conghuy.talkwithme.data.sqlmodel.SqlData;
import vn.conghuy.talkwithme.data.sqlmodel.WordModel;
import vn.conghuy.talkwithme.responsor.NormalResponsorManager;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.ListView;

import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.AsyncFacebookRunner.RequestListener;
import com.facebook.android.DialogError;
import com.facebook.android.Facebook.DialogListener;
import com.facebook.android.FacebookError;

public class TalkWithMeActivity extends Activity implements TextToSpeech.OnInitListener{
    /** Called when the activity is first created. */
	private static final int RECOR_SPEECH_REQUEST_CODE = 1;
	private static final int TEMPLATE_REQUEST_CODE = 2;
	
	
	ArrayList<String> wolframKeys;
	
	private static final int ABOUT_DIALOG_ID = 1;
	private static final int RECOGNIZER_NOT_PRESENT_DIALOG_ID = 2;
	
	
    private ListView wordsList;
    private Button bSend;
    private AutoCompleteTextView eInput;
    Button speakButton;
    Button bShowHideInput;
    CustomAdapter adapter;
    MyHandler handler;					// use to interact with UI in child thread
    TextToSpeech tts;
    NormalResponsorManager responsorMgr;
    String[] greetStrings;
    String[] foundResultStrings;
    MyApp myApp;
    Menu menu;
    boolean hasRecognizer;
    
    /**
     * Called with the activity is first created.
     */
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.voice_recog);
        
        DatabaseHelper dbHelper = DatabaseHelper.GetInstanceAndInit(this);
        dbHelper.startDatabase();
        
        tts = new TextToSpeech(this, this);
        SqlData.load();
        handler = new MyHandler();
        wolframKeys = new ArrayList<String>();
        loadWolframKeysFromLocal();
        
        greetStrings = WordModel.GetWordsByAction("greet");
        foundResultStrings = WordModel.GetWordsByAction("found result");
 
        speakButton = (Button) findViewById(R.id.speakButton);
        speakButton.setOnClickListener(myOnClickListener);
        bShowHideInput = (Button)findViewById(R.id.b_show_template);
        bShowHideInput.setOnClickListener(myOnClickListener);
        wordsList = (ListView) findViewById(R.id.list);
        bSend = (Button)findViewById(R.id.b_send);
        bSend.setOnClickListener(myOnClickListener);
        eInput = (AutoCompleteTextView) findViewById(R.id.e_input);
        eInput.setText("");
        eInput.setVisibility(View.GONE);
		bSend.setVisibility(View.GONE);
        
        myApp = (MyApp)getApplicationContext();
        myApp.mainActivity = this;
 
        // Disable button if no recognition service is present
        PackageManager pm = getPackageManager();
        List<ResolveInfo> activities = pm.queryIntentActivities(
                new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
        if (activities.size() == 0)
        {
            speakButton.setText(R.string.recog_not_present);
            hasRecognizer = false;
            //Utils.ShowToast(this, R.string.recog_not_present_detail);
            showDialog(RECOGNIZER_NOT_PRESENT_DIALOG_ID);
        }
        else{
        	hasRecognizer = true;
        }
        
        createResponsorManager();
        
        adapter = new CustomAdapter(this);
        wordsList.setAdapter(adapter);
        
        if(Utils.isInternetConnected(this) == false){
        	Utils.ShowToast(this, R.string.no_internet_alert);
        }
        
        Thread updateListKeyThread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				if(Utils.isInternetConnected(TalkWithMeActivity.this) == true){
		        	updateAndSaveWolframKeysToLocal();
		        }
			}
		});
        updateListKeyThread.start();
    }
    
    void createResponsorManager(){
    	responsorMgr = new NormalResponsorManager();
    	responsorMgr.setContext(this);
    	responsorMgr.setWolframApiKey(getWolframKey());
    	responsorMgr.create();
    }
    
    String getWolframKey(){
    	int numWolframKey = wolframKeys.size();
    	Random rand = new Random();
    	int index = rand.nextInt(numWolframKey);
    	return wolframKeys.get(index);
    }
    View.OnClickListener myOnClickListener = new View.OnClickListener() {
		
		public void onClick(View v) {
			switch (v.getId()) {
			
			case R.id.speakButton:
				if(hasRecognizer){
					tts.stop();
					startVoiceRecognitionActivity();
				}
				else{
					Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=com.google.android.voicesearch"));
					startActivity(intent);
				}
				break;
				
			case R.id.b_send:
				
				String input = eInput.getText().toString();
				
				if(input.equals("") == false){
					eInput.setText("");
					processRequestAndAddToList(input);
				}
				else{
					Utils.ShowToast(TalkWithMeActivity.this, R.string.please_input_request);
				}
				break;
				
			case R.id.b_show_template:
				Intent intent = new Intent(getBaseContext(), TemplateActivity.class);
				startActivityForResult(intent, TEMPLATE_REQUEST_CODE);
				break;

			default:
				break;
			}
			
		}
	};
 
 
    /**
     * Fire an intent to start the voice recognition activity.
     */
    private void startVoiceRecognitionActivity()
    {
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.talk_with_me));
        startActivityForResult(intent, RECOR_SPEECH_REQUEST_CODE);
    }
 
    /**
     * Handle the results from the voice recognition activity.
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
    	myApp.facebook.getFacebook().authorizeCallback(requestCode, resultCode, data);
    	
    	if(resultCode == RESULT_OK){
	        if (requestCode == RECOR_SPEECH_REQUEST_CODE)
	        {
	            // Populate the wordsList with the String values the recognition engine thought it heard
	            ArrayList<String> matches = data.getStringArrayListExtra(
	                    RecognizerIntent.EXTRA_RESULTS);
	        	processRequestAndAddToList(matches.get(0));
	        }
	        else if(requestCode == TEMPLATE_REQUEST_CODE){
	        	eInput.setText(data.getStringExtra("text"));
	        	eInput.setVisibility(View.VISIBLE);
				bSend.setVisibility(View.VISIBLE);
	        }
	        
    	}
        super.onActivityResult(requestCode, resultCode, data);
    }
    
    @SuppressLint("NewApi")
	private void addTextToList(String text){
    	adapter.addItem(text);
    	wordsList.smoothScrollToPosition(wordsList.getCount()-1);
    }
    
    private void processRequestAndAddToList(final String input){
    	addTextToList("<i><b>" + getString(R.string.you) + "</b> : " + input + "</i>");
    	Thread requestThread = new Thread(new Runnable() {
			
			public void run() {
				String result = request(input);
				Message msg = new Message();
				Bundle data = new Bundle();
				data.putString("textAddToList", result);
				msg.setData(data);
		    	handler.sendMessage(msg);
			}
		});
    	requestThread.start();
    	
    }
    
    private String request(String query){
    	String result = responsorMgr.Response(query);
    	if(result != null)
    		return result;
    	else return getString(R.string.command_null_result);
    }
    
    @SuppressLint("HandlerLeak")
	class MyHandler extends Handler{
    	@Override
    	public void handleMessage(Message msg) {
    		Bundle data = msg.getData();
    		String textAddToList = data.getString("textAddToList");
    		textAddToList = textAddToList.replace("\n", "<br>");
    		addTextToList(textAddToList);
    		
    		//speak plaintext
    		if(vn.conghuy.talkwithme.utils.Utils.isTextBePlain(textAddToList)){
    			textAddToList = textAddToList.replace("<b>", "");
    			textAddToList = textAddToList.replace("</b>", "");
    			textAddToList = textAddToList.replace("<br>", ". ");
    			speak(textAddToList);
    		}
    		// speak "found result"
    		else{
    			speak(vn.conghuy.talkwithme.utils.Utils.getRandomString(foundResultStrings));
    		}
    		super.handleMessage(msg);
    	}
    }

	public void onInit(int status) {
		 if (status == TextToSpeech.SUCCESS) {
            int result = tts.setLanguage(Locale.US);
            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Log.e("DEBUG", "Language is not available.");
            } else {
            	speak(vn.conghuy.talkwithme.utils.Utils.getRandomString(greetStrings));
            }
        } else {
            Log.e("DEBUG", "Could not initialize TextToSpeech.");
        }
	}
	
	void speak(String text){
		tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
	}
	
	@Override
	protected void onDestroy() {
		if (tts != null) {
            tts.stop();
            tts.shutdown();
        }
		super.onDestroy();
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		myApp.mainActivityResume();
		//createResponsorManager();
		responsorMgr.reset();
		myApp.enableOrientationSensor(true);
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		myApp.enableOrientationSensor(false);
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		this.menu = menu;
		MenuInflater inflater = getMenuInflater();
	    inflater.inflate(R.menu.main_menu, menu);
	    
	    MenuItem menuLoginOutFacebok = menu.findItem(R.id.login_logout_facebook);
	    if(myApp.facebook.isLogin()){
	    	loginFacebook();
	    }
	    else menuLoginOutFacebok.setTitle(R.string.login_facebook);
	    
	    return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.show_hide_option:
			if(eInput.getVisibility() == View.VISIBLE){
				eInput.setVisibility(View.GONE);
				bSend.setVisibility(View.GONE);
			}
			else{
				eInput.setVisibility(View.VISIBLE);
				bSend.setVisibility(View.VISIBLE);
			}
			break;

		case R.id.login_logout_facebook:
			if(myApp.facebook.isLogin() == true){
				logoutFacebook();
			}
			else{
				loginFacebook();
			}
			break;
		case R.id.about_menu:
			showDialog(ABOUT_DIALOG_ID);
			break;
		}
		return true;
	}
	
	public void loginFacebook(){
		final SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
		
		String accessToken = mPrefs.getString("access_token", null);
		long accessExpires = mPrefs.getLong("access_expires", 0);
		myApp.facebook.setAccessToken(accessToken);
		myApp.facebook.setAccessExpires(accessExpires);
        
		if(accessToken != null) {
            myApp.facebook.getFacebook().setAccessToken(accessToken);
        }
        if(accessExpires != 0) {
        	myApp.facebook.getFacebook().setAccessExpires(accessExpires);
        }
        if(myApp.facebook.isLogin()){
        	runOnUiThread(new Runnable() {
				
				public void run() {
					menu.findItem(R.id.login_logout_facebook).setTitle(R.string.logout_facebook);
					menu.findItem(R.id.login_logout_facebook).setIcon(R.drawable.facebook_icon);
					Utils.ShowToast(TalkWithMeActivity.this, R.string.login_facebook_success);
				}
			});
        }
        
        if(!myApp.facebook.getFacebook().isSessionValid()) {
        	myApp.facebook.getFacebook().authorize(myApp.mainActivity, new String[]{"publish_stream", "manage_notifications"}, new DialogListener() {
                public void onComplete(Bundle values) {
                	
                	String accessToken = myApp.facebook.getFacebook().getAccessToken();
                	long accessExpires = myApp.facebook.getFacebook().getAccessExpires();
                	myApp.facebook.setAccessToken(accessToken);
            		myApp.facebook.setAccessExpires(accessExpires);
            		
                    SharedPreferences.Editor editor = mPrefs.edit();
                    editor.putString("access_token", accessToken);
                    editor.putLong("access_expires", accessExpires);
                    editor.commit();
                    
                    if(myApp.facebook.isLogin()){
                    	runOnUiThread(new Runnable() {
							
							public void run() {
								menu.findItem(R.id.login_logout_facebook).setTitle(R.string.logout_facebook);
								menu.findItem(R.id.login_logout_facebook).setIcon(R.drawable.facebook_icon);
								Utils.ShowToast(TalkWithMeActivity.this, R.string.login_facebook_success);
							}
						});
                    	
                    }
                }
    
                public void onFacebookError(FacebookError error) {}
    
                public void onError(DialogError e) {}
    
                public void onCancel() {}
            });
        }
	}
	
	public void logoutFacebook(){
		AsyncFacebookRunner mAsyncRunner = myApp.facebook.getAsincFacebookRunner();
   		mAsyncRunner.logout(this, new RequestListener() {

		  public void onComplete(String response, Object state) 
		  {
			  SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(TalkWithMeActivity.this);
		   		myApp.facebook.setAccessToken(null);
		   		myApp.facebook.setAccessExpires(0);
		   		
		        SharedPreferences.Editor editor = mPrefs.edit();
		        editor.putString("access_token", null);
		        editor.putLong("access_expires", 0);
		        editor.commit();
		        
			  if(myApp.facebook.isLogin() == false){
				  runOnUiThread(new Runnable() {
					
					public void run() {
						menu.findItem(R.id.login_logout_facebook).setTitle(R.string.login_facebook);
						menu.findItem(R.id.login_logout_facebook).setIcon(R.drawable.facebook_icon_gray);
						Utils.ShowToast(TalkWithMeActivity.this, R.string.logout_facebook_success);
					}
				});
              	
              }
		  }
		  
		  public void onIOException(IOException e, Object state) {}
		  
		  public void onFileNotFoundException(FileNotFoundException e,Object state) {}
		  
		  public void onMalformedURLException(MalformedURLException e,Object state) {}
	
		  public void onFacebookError(FacebookError e, Object state) {}
   		});
   }
	
	@Override
	@Deprecated
	protected Dialog onCreateDialog(int id) {
		AlertDialog.Builder dialog = new AlertDialog.Builder(this);
		
		switch(id){
		
		case ABOUT_DIALOG_ID:
		
			dialog.setTitle(R.string.about);
			dialog.setMessage(R.string.about_body);
			dialog.setIcon(R.drawable.about);
			dialog.setPositiveButton(R.string.rate_app, new DialogInterface.OnClickListener() {
				
				@Override
				public void onClick(DialogInterface dialog, int which) {
					Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=vn.conghuy.talkwithme"));
					startActivity(intent);
				}
			});
			dialog.setNeutralButton(R.string.feedback, new DialogInterface.OnClickListener() {
				
				@Override
				public void onClick(DialogInterface dialog, int which) {
					Intent emailIntent = new Intent(Intent.ACTION_SEND);
					emailIntent.setType("text/html");
					
					String[] emailArray = new String[1];
					emailArray[0] = getString(R.string.feedback_email);
					
					emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, emailArray );
					emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.feedback_email_title ));
					startActivity(emailIntent);
				}
			});
			dialog.setNegativeButton(android.R.string.ok, null);
			return dialog.create();
			
		case RECOGNIZER_NOT_PRESENT_DIALOG_ID:
			dialog.setTitle(R.string.notice);
			dialog.setMessage(R.string.recog_not_present_message_box_body);
			dialog.setIcon(android.R.drawable.ic_dialog_alert);
			dialog.setPositiveButton(R.string.download_now, new DialogInterface.OnClickListener() {
				
				@Override
				public void onClick(DialogInterface dialog, int which) {
					Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=com.google.android.voicesearch"));
					startActivity(intent);
				}
			});
			
			dialog.setNegativeButton(android.R.string.cancel, null);
			return dialog.create();
		}
		
		return null;
	}
	
	void updateAndSaveWolframKeysToLocal(){
		String html = vn.conghuy.talkwithme.utils.Utils.requestHtmlContent(getString(R.string.wolframs_keys_link));
		if(html != null){
			String keys[] = html.split("\n");
			
			wolframKeys.clear();
			for(String key : keys){
				wolframKeys.add(key);
			}
			
			if(wolframKeys.size() == 0)
				addDefaultWolfarmKey();
			
			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
			SharedPreferences.Editor edit = prefs.edit();
			edit.putInt("numKey", wolframKeys.size());
			for(int i = 0; i < wolframKeys.size(); i++){
				edit.putString("wolKey"+i, wolframKeys.get(i));
			}
			edit.commit();
		}
	}
	
	void loadWolframKeysFromLocal(){
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		int size = prefs.getInt("numKey", 0);
		for(int i = 0; i < size; i++){
			String key = prefs.getString("wolKey"+i, "");
			wolframKeys.add(key);
		}
		if(wolframKeys.size() == 0)
			addDefaultWolfarmKey();
	}
	
	void addDefaultWolfarmKey(){
		wolframKeys.add(getString(R.string.default_wolfram_key));
		wolframKeys.add(getString(R.string.default_wolfram_key_2));
		wolframKeys.add(getString(R.string.default_wolfram_key_3));
		wolframKeys.add(getString(R.string.default_wolfram_key_4));
	}
}